// MyArray.h

// insure that this header file is not included more than once
#pragma once
#ifndef MYARRAY_H_
#define MYARRAY_H_

template <class elemType>
class MyArray
{
private:
      int _size; // number of elements the current instance is holding
      int _capacity; // number of elements the current instance can hold
      elemType * list; // ptr to the first element in the array

// UtILITY FUNCTION(S)
// MakeRoom
      // doubles _capacity and builds a new list
      //   maintains current data
      void MakeRoom();


public:

	// Incrementer
	  // Increases size by 1
	  void IncrementSize();

// Ctors
      MyArray(); // default
      MyArray(int capacity); // initialize to capacity
      MyArray( MyArray & original); // copy constructor

// Dtor
      ~MyArray();

// METHODS
// Add
      // Takes an argument of the templated type and
      // adds it to the end of the list/array
      void Add(const elemType & elem);

// At
      // Takes an int argument
      // Returns a reference to the element at a specified location in this MyArray
      elemType & At(int index);

// Find
      // Takes an argument of the templated type
      // Returns the int index were this element is found
      // Returns -1 if element is not found
      int Find(const elemType & elem);

// Insert
      //Takes an argument of the templated type and
      // An integer index argument
      // Inserts the element at that index in the list/array
      // moving the element currently at that index and all subsequent
      // elements up one index
      void Insert(const elemType & elem, int index);

// RemoveAt
      // Takes an int argument
      // Removes the element at that index in the list/array
      void RemoveAt(int index);

// SetValue
      // Takes an item to assign and an int index to assign it at
      // Assigns the item to the specified index of this MyArray
      void SetValue(const elemType & elem, int index);

// Size
      // Returns the number of elements in this MyArray
      int Size();

// OPERATORS
      // = (assignment - takes a MyArray and makes a deep copy)
      MyArray & operator= (const MyArray & aMyArray);

      // [] (read/write char access by index)
            // Returns a reference to the element at that index
            // throws an exception if index is < 0 or >= _length
      elemType & operator[] (int index) const;

      // ==, != (boolean relational test operators)
      //  compares arrays for element by element equality
      bool operator== (const MyArray & aMyArray) ;
      bool operator!= (const MyArray & aMyArray) ;
};
#endif


template <class elemType> void  MyArray<elemType>::MakeRoom()
{
	MyArray<elemType> _list(_capacity);

	for (int i = 0; i < _capacity; i++)
	{
		_list.list[i] =  list[i];
	}

	_capacity = _capacity * 2;
	delete [] list;
	list = new elemType[_capacity];

	for (int i = 0; i < _capacity; i++)
	{
		list[i] =  _list.list[i];
	}
}


// Ctors
// default
template <class elemType> MyArray<elemType>::MyArray()
{
	_size = 0;
	_capacity = 16;
	list = new elemType[_capacity];
	

}

// initialize to capacity
template <class elemType> MyArray<elemType>::MyArray(int capacity) 
{
	_size = 0;
	_capacity = capacity;
	list = new elemType[_capacity];

}

// copy constructor
template <class elemType> MyArray<elemType>::MyArray( MyArray & original) 
{
	_size = original._size;
	_capacity = original._capacity;
	list = new elemType[_capacity];
	
}

// Dtor
template <class elemType> MyArray<elemType>::~MyArray()
{
	delete [] list;
}

// METHODS
// Incrementer
	  // Increases size by 1
template <class elemType> void MyArray<elemType>::IncrementSize()
{
	_size++;
}
// Add
      // Takes an argument of the templated type and
      // adds it to the end of the list/array
template <class elemType> void MyArray<elemType>::Add(const elemType & elem)
{
	if (_size + 1 > _capacity)
	{
		this->MakeRoom();
	}

	list[_size] = elem;
	_size++;
}

// At
      // Takes an int argument
      // Returns a reference to the element at a specified location in this MyArray
template <class elemType> elemType & MyArray<elemType>::At(int index)
{
	return list[index];
}

// Find
      // Takes an argument of the templated type
      // Returns the int index were this element is found
      // Returns -1 if element is not found
template <class elemType> int MyArray<elemType>::Find(const elemType & elem)
{
	int x = 0;
	do
	{
		if (elem == list[x])
			return x;
		else
			x++;
	}while(x <= _size);

	return -1;
}

// Insert
      // Takes an argument of the templated type and
      // An integer index argument
      // Inserts the element at that index in the list/array
      // moving the element currently at that index and all subsequent
      // elements up one index
template <class elemType> void MyArray<elemType>::Insert(const elemType & elem, int index)
{
	for (int i = _size; i >= index; i--)
	{
		list[i+1] = list[i];
	}
	list[index] = elem;
	_size++;
}

// RemoveAt
      // Takes an int argument
      // Removes the element at that index in the list/array
template <class elemType> void MyArray<elemType>::RemoveAt(int index)
{
	for (int i = index; i <= _size; i++)
	{
		list[i]=list[i+1];
	}
	_size--;
}

// SetValue
      // Takes an item to assign and an int index to assign it at
      // Assigns the item to the specified index of this MyArray
template <class elemType> void MyArray<elemType>::SetValue(const elemType & elem, int index)
{
	list[index] = elem;
}

// Size
      // Returns the number of elements in this MyArray
template <class elemType> int MyArray<elemType>::Size()
{
	return _size;
}

// OPERATORS
      // = (assignment - takes a MyArray and makes a deep copy)
template <class elemType> MyArray<elemType> & MyArray<elemType>::operator= (const MyArray & aMyArray)
{
	_size = aMyArray._size;
	_capacity = aMyArray._capacity;

	do
	{
	if (aMyArray.size > _capacity)
		this->MakeRoom();
	} while (aMyArray.Size > _capacity);

	for (int i =  0; i <= aMyArray._size;i++)
		list[i] = aMyArray.list[i];
}

// [] (read/write char access by index)
   // Returns a reference to the element at that index
   // throws an exception if index is < 0 or >= _length
template <class elemType> elemType &  MyArray<elemType>::operator[] (int index) const
{
	if (index >= 0 && index <= _size)
		return list[index];
	else
		throw "Index out of bounds";
}

// ==, != (boolean relational test operators)
//  compares arrays for element by element equality
template <class elemType> bool MyArray<elemType>::operator== (const MyArray & aMyArray) 
{
	if (_size > aMyArray._size || aMyArray._size > _size)
		return false;

	for (int i = 0; i < _size; i++)
	{
	if (list[i] == aMyArray[i])

	else
		return false;
	}

	return true;
}

template <class elemType> bool MyArray<elemType>::operator!= (const MyArray & aMyArray) 
{

	if (_size > aMyArray._size || aMyArray._size > _size)
		return true;

	for (int i = 0; i < _size; i++)
	{
	if (list != aMyArray)
		
	else
		return true;
	}

	return false;
}
